/*
*    Phantom Test Driver v2.0 GUI Automation Software
*    Copyright (C) 2009  John C. Van Arsdall (john@phantomtest.com)
*
*    This program is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License along
*    with this program; if not, write to the Free Software Foundation, Inc.,
*    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
/*
 * PTDDecls.java
 *
 * Created on August 3, 2007, 5:03 PM
 *
 * To change this template, choose Tools | Options and locate the template under
 * the Source Creation and Management node. Right-click the template and choose
 * Open. You can then make changes to the template in the Source Editor.
 */

package ptd;

import javax.swing.tree.*;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.CellEditor;
import java.awt.Component;
import javax.swing.event.CellEditorListener;
import javax.swing.JLabel;
import java.awt.event.*;
import java.util.EventObject;

import java.awt.dnd.*;
import java.awt.datatransfer.Transferable;
import java.awt.Cursor;

import javax.swing.JPopupMenu;
import javax.swing.JMenuItem;
import javax.swing.Icon;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Color;

//import java.io.FileInputStream;
//import java.io.FileOutputStream;

import java.io.*;

import java.util.Vector;
import javax.swing.JMenu;
import javax.swing.JOptionPane;
import javax.swing.MenuElement;
import javax.swing.UIManager;
import ptd_decl_objects.*;



/**
 *
 * @author John
 */
public class PTDDecls extends JTree implements DragGestureListener, DragSourceListener{

    public JPopupMenu DeclsPopup;
    JMenuItem InsertChild;
    JMenuItem InsertBefore;
    JMenuItem InsertAfter;
    
    JMenu EditMenu;
    JMenuItem EditCopyMenu;
    JMenuItem EditPasteInMenu;
    JMenuItem EditPasteAfterMenu;
    JMenuItem EditPasteBeforeMenu;
    JMenuItem EditDeleteMenu;

    JMenuItem InsertChildParent;
    JMenuItem InsertBeforeParent;
    JMenuItem InsertAfterParent;
    
    JMenu EditMenuParent;
    JMenuItem EditCopyMenuParent;
    JMenuItem EditPasteInMenuParent;
    JMenuItem EditPasteAfterMenuParent;
    JMenuItem EditPasteBeforeMenuParent;
    JMenuItem EditDeleteMenuParent;
    
    
    public PTDMain pW;

    private DefaultMutableTreeNode m_CopyNodes = null;
    private DragSource dragSource;
    private boolean bStaticUI;

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    public void setParent(PTDMain In){
        pW = In;
    }
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    public void addFile(String fileName){
        try{
            File aFile = new File(fileName);
            BufferedReader aReader = new BufferedReader (new FileReader(aFile));
            
            DeclBase newBase = new DeclBase();
            PTDDeclInfo newInfo = new PTDDeclInfo();
            newBase.myName = fileName;
            newBase.myType = DeclBase.TYPE_FILE;
            newInfo.init(newBase);
            DefaultMutableTreeNode newRoot = new DefaultMutableTreeNode(newInfo, true);

            newRoot = loadTreeNode(aReader, newRoot);
            DefaultMutableTreeNode currRoot = (DefaultMutableTreeNode)((DefaultTreeModel)treeModel).getRoot();
            if(newRoot != null){
                if(currRoot == null){
                    setSelectionPath(null);
                    ((DefaultTreeModel)treeModel).setRoot(newRoot);
                }else{
                    ((DefaultTreeModel)treeModel).insertNodeInto(newRoot, currRoot, currRoot.getChildCount());
                    scrollPathToVisible(new TreePath(newRoot.getPath()));
                    setSelectionPath(new TreePath(newRoot.getPath()));
                }
            }else{
                PTDMessageBox.MessageBox("Could not load declarations file: " + fileName);
                Main.debug_out("Could not load Declarations");
            }
            aReader.close();
            //updateUI();
            
        }catch (Exception e){
            PTDMessageBox.MessageBox("Could not load declarations file: " + fileName);
            Main.debug_out(e.getMessage());
        }
    }
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    public void saveAll(){
        DefaultMutableTreeNode Root = (DefaultMutableTreeNode)((DefaultTreeModel)treeModel).getRoot();
        if(Root.getChildCount() > 0){
            DefaultMutableTreeNode Child = (DefaultMutableTreeNode)Root.getFirstChild();
            while(Child != null){
                PTDDeclInfo aDecl = (PTDDeclInfo) Child.getUserObject();
                if(aDecl != null){
                    if(aDecl.myData.myType == DeclBase.TYPE_FILE){
                        saveFile(aDecl.myData.myName, Child);
                    }
                }
                Child = Child.getNextSibling();
            }
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    public void saveFile(String fileName, DefaultMutableTreeNode Top){
        try{
            
            if(Top==null){
                Top = getSelectedDeclarations();
            }
            
            if(Top  == null){
                PTDMessageBox.MessageBox("No Declarations Selected");
                return;
            }
            
            DeclBase aBase = new DeclBase();
            PTDDeclInfo anInfo;
            aBase.myName = fileName;
            PTDDeclInfo restoreInfo = (PTDDeclInfo)Top.getUserObject();
            if(fileName.length() == 0){
                anInfo = (PTDDeclInfo)Top.getUserObject();
                fileName = anInfo.myData.myName;
            }else{
                anInfo = new PTDDeclInfo();
                anInfo.init(aBase);
            }

            File aFile = new File(fileName);
            BufferedWriter aWriter = new BufferedWriter (new FileWriter(aFile));

            
            if(Top.getChildCount() > 0){
                DefaultMutableTreeNode Child = (DefaultMutableTreeNode)Top.getFirstChild();
                while(Child != null){
                    if(!saveTreeNode(aWriter, Child, 0)){
                        Main.debug_out("Could not save declarations");
                        return;
                    }
                    Child = Child.getNextSibling();
                }
            }

            anInfo.myData.bModifiedFlag = false;
            
            
            aWriter.close();
            Top.setUserObject(restoreInfo);
            
            
            //DefaultMutableTreeNode Par = (DefaultMutableTreeNode)Top.getParent();
            //PTDDeclInfo ParInfo = (PTDDeclInfo)Par.getUserObject();
            //ParInfo.myData.bModifiedFlag = false;
            //Par.setUserObject(ParInfo);
            
            DefaultTreeModel model = (DefaultTreeModel)getModel();
            model.nodeChanged(Top);
            model.nodeStructureChanged(Top);  // Else wont update the modified *... must be a better way!
            
            setSelectionPath(new TreePath(Top.getPath()));

            //updateUI();
            
        }catch (Exception e){
            Main.debug_out(e.getMessage());
        }
    }

    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    public void closeFile(){
        try{            
            DefaultMutableTreeNode Top = getSelectedDeclarations();
            PTDDeclInfo anInfo = (PTDDeclInfo)Top.getUserObject();
            setSelectionRow(0);
            ((DefaultTreeModel)treeModel).removeNodeFromParent(Top);
        }catch (Exception e){
            Main.debug_out(e.getMessage());
        }
    }

    public Vector<String> getLoadedDecs(){
        
        Vector<String> Ret = new Vector<String>();
        DefaultMutableTreeNode Root = (DefaultMutableTreeNode)((DefaultTreeModel)treeModel).getRoot();
        if(Root.getChildCount() > 0){
            DefaultMutableTreeNode Child = (DefaultMutableTreeNode)Root.getFirstChild();
            while(Child != null){
                PTDDeclInfo aDecl = (PTDDeclInfo) Child.getUserObject();
                if(aDecl != null){
                    if(aDecl.myData.myType == DeclBase.TYPE_FILE){
                        Ret.add(aDecl.myData.myName);
                    }
                }
                Child = Child.getNextSibling();
            }
        }
        
        return Ret;
    }
    
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    public DefaultMutableTreeNode loadTreeNode(BufferedReader In, DefaultMutableTreeNode Top){
        DeclBase NewItem = new DeclBase();
        DefaultMutableTreeNode CurrNode = Top;
        int iLevel = 0;
        int LastLevel = 0;
        int Move = 0;
        
        while((iLevel = NewItem.load(In)) != 0){
            PTDDeclInfo newInfo = new PTDDeclInfo();
            newInfo.init(NewItem);
            DefaultMutableTreeNode Node = new DefaultMutableTreeNode(newInfo, true);
            if(iLevel == 1){
                Top.insert(Node, Top.getChildCount());
                CurrNode = Top;
                LastLevel = 1;
            }else{
                Move = iLevel - LastLevel;
                if(Move == 0){
                    CurrNode.insert(Node, CurrNode.getChildCount());
                }else if(Move < 0){
                    while(Move < 0){
                        CurrNode = (DefaultMutableTreeNode)CurrNode.getParent();
                        Move = Move + 1;
                        if(CurrNode == Top){  // Cant go above top...
                            iLevel = 1;
                            Move = 0;
                        }
                    }
                    CurrNode.insert(Node, CurrNode.getChildCount());
                }else if(Move == 1){
                    CurrNode = (DefaultMutableTreeNode)CurrNode.getChildAt(CurrNode.getChildCount()-1); // Get last child
                    if(CurrNode == null){
                        return null;
                    }
                    CurrNode.insert(Node, CurrNode.getChildCount());
                }else{
                    // Cant go more than one level deeper
                    return null;
                }
                LastLevel = iLevel;
                if(LastLevel <= 0){
                    LastLevel = 1;
                }
            }
            NewItem = new DeclBase();
        }
        
        return Top;
    }

    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    public boolean saveTreeNode(BufferedWriter Out, DefaultMutableTreeNode Top, int iLevel){
        
        if(Top == null){
            return false;
        }
        DefaultMutableTreeNode CurrNode = Top;
        PTDDeclInfo NewItem = (PTDDeclInfo)Top.getUserObject();
        NewItem.myData.save(Out, iLevel);
        
        if(Top.getChildCount() > 0){
            DefaultMutableTreeNode Child = (DefaultMutableTreeNode)Top.getFirstChild();
            while(Child != null){
                if(!saveTreeNode(Out, Child, iLevel+1)){
                    return false;
                }
                Child = Child.getNextSibling();
            }
        }
        
        return true;
    }
    
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    private DefaultMutableTreeNode getSelectedTreeNode(){
        TreePath SelPath = getSelectionPath();
        if(SelPath == null){
            return null;
        }
        DefaultMutableTreeNode SelNode = (DefaultMutableTreeNode)SelPath.getLastPathComponent();
        if(SelNode == null){
            return null;
        }
        return SelNode;
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    private DefaultMutableTreeNode getSelectedDeclarations(){
        DefaultMutableTreeNode currRoot = (DefaultMutableTreeNode)((DefaultTreeModel)treeModel).getRoot();
        DefaultMutableTreeNode SelNode = getSelectedTreeNode();
        if(SelNode == null){
            return null;
        }
        if(SelNode == currRoot){
            return null;
        }
        while(SelNode.getParent() != currRoot){
            SelNode = (DefaultMutableTreeNode)SelNode.getParent();
        }
        return SelNode;
    }
    
    
   public void dragDropEnd(DragSourceDropEvent dtde) {
       
   }
    
   public void dragExit(DragSourceEvent dtde) {
       
   }
   
   public void dragEnter(DragSourceDragEvent dtde) {
       
   }
   
   public void dragOver(DragSourceDragEvent dtde) {
       
   }
   
   public void dropActionChanged(DragSourceDragEvent dtde) {
       
   }
    
    public void dragGestureRecognized(DragGestureEvent e) {
        DefaultMutableTreeNode dragNode = getSelectedTreeNode();
        DeclBase transferBase = new DeclBase();
        transferBase.myName = "";
        
        DefaultMutableTreeNode currRoot = (DefaultMutableTreeNode)((DefaultTreeModel)treeModel).getRoot();
        
        if (dragNode != null) {
            if(dragNode == currRoot){
                transferBase.myName = "";
            }else if(dragNode.getParent() == currRoot){
                PTDDeclInfo aDecl = (PTDDeclInfo) dragNode.getUserObject();
                String sFile = aDecl.myData.myName;
                sFile = sFile.replace("\\", "\\\\");
                transferBase.myName = "use \"" + sFile + "\";\n";
            }else{
                while(dragNode.getParent() != currRoot){
                    PTDDeclInfo aDecl = (PTDDeclInfo) dragNode.getUserObject();
                    if(aDecl.myData.isUseable){ // do this to avoid menu tops
                        transferBase.myName = aDecl.myData.myName + "." + transferBase.myName;
                    }
                    dragNode = (DefaultMutableTreeNode)dragNode.getParent();
                }
            }
            
            
            Cursor cursor = DragSource.DefaultCopyNoDrop;
            int action = e.getDragAction();
            if (action == DnDConstants.ACTION_MOVE){
                //cursor = DragSource.DefaultMoveNoDrop;
                cursor = DragSource.DefaultMoveDrop;
            }
            
            //Cursor cursor = selectCursor (e.getDragAction());
            //DragSource dragSource = e.getDragSource();
            //try{
                dragSource.startDrag(e, cursor, transferBase, this);
            //}catch (Exception err){
            //    Main.debug_out("Error: " + err.getMessage());
            //}

        }
    }
    
    public void selectItem(DefaultMutableTreeNode selNode, DefaultMutableTreeNode oldNode){
        if(selNode == null){
            return;
        }
        
         PTDDeclInfo anInfo = (PTDDeclInfo)selNode.getUserObject();     
         if(anInfo == null){
             return;
         }
         
         DeclBase oldBase = pW.getDeclProps();
         if(oldBase != null){
             if(oldBase.bModifiedFlag){
                oldBase.bModifiedFlag = false;
                setModified(oldNode);
             }
         }

         DefaultTreeModel model = (DefaultTreeModel)getModel();
         if(oldNode != null){
             PTDDeclInfo oldInfo = (PTDDeclInfo)oldNode.getUserObject();     
             if(oldInfo != null){
                 oldInfo.myFrame.update(oldInfo.myData);
             }
             model.nodeChanged(oldNode);  
         }
         
         //anInfo.myFrame.update(anInfo.myData);
         //model.nodeChanged(selNode);
         
         pW.setDeclProps(anInfo.myData);
    }
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    private void setModified(DefaultMutableTreeNode modNode){
        DefaultMutableTreeNode topNode = getFileNode(modNode);
        if(topNode != null){
            PTDDeclInfo anInfo = (PTDDeclInfo)topNode.getUserObject();
            anInfo.myData.bModifiedFlag = true;
            DefaultTreeModel model = (DefaultTreeModel)getModel();
            model.nodeChanged(topNode);  
        }
        //anInfo.bModifiedFlag = bModified;
    }
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    private DefaultMutableTreeNode getFileNode(DefaultMutableTreeNode inNode){
        if(inNode != null){
            PTDDeclInfo anInfo = (PTDDeclInfo)inNode.getUserObject();
            if(anInfo.myData.myType == anInfo.myData.TYPE_FILE){
                return inNode;
            }else{
                return getFileNode((DefaultMutableTreeNode)inNode.getParent());
            }
        }else{
            return null;
        }
    }
    
    /** Creates a new instance of PTDDecls */
    public PTDDecls() {
        bStaticUI = true;
        PTDDeclsCell CellEdit = new PTDDeclsCell();
        PTDDeclsRender CellRender = new PTDDeclsRender();
        
        addMouseListener(new PTDDeclsMouseListener());
        
        
        FocusListener myFocusListener = new FocusListener(){
            public void focusGained(FocusEvent e){
                //DefaultMutableTreeNode aNode = getSelectedTreeNode();
                //if(aNode != null){
                //    PTDDeclInfo anInfo = (PTDDeclInfo)aNode.getUserObject();
                //    if(anInfo.myData.myType == anInfo.myData.TYPE_WIN){
                //        EnableParentMenus(true);
                //        Main.debug_out("Enabling Parent Menus");
                //    }
                //}
                
            }
            public void focusLost(FocusEvent e){
                //Main.debug_out("Disabling Parent Menus");
                //EnableParentMenus(false);
            }
        };
        
        
        this.addFocusListener(myFocusListener);
        
        this.showsRootHandles = true;
        setSelectionPath(null);
        ((DefaultTreeModel)treeModel).setRoot(null);
        
        //m_CopyNodes = null;
        
        setEditable(true);
        this.setEnabled(true);
        this.setVisible(true);
 
        setCellRenderer(CellRender);
        setCellEditor(CellEdit);
        
        GenerateMenus();
        
        getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
        
        // Following is from java top 97 code...-----------
        dragSource = DragSource.getDefaultDragSource() ;
    
        DragGestureRecognizer dgr = dragSource.createDefaultDragGestureRecognizer(
            this,                             //DragSource
            DnDConstants.ACTION_COPY_OR_MOVE, //specifies valid actions
            this                              //DragGestureListener
        );

        /* Eliminates right mouse clicks as valid actions - useful especially
        * if you implement a JPopupMenu for the JTree
        */
        //dgr.setSourceActions(dgr.getSourceActions() & ~InputEvent.BUTTON3_MASK);
        // --------------------------------------------------

        initTree();

        addTreeSelectionListener(new TreeSelectionListener(){
           public void valueChanged(TreeSelectionEvent e){
               DefaultMutableTreeNode node = (DefaultMutableTreeNode)getLastSelectedPathComponent();
               DefaultMutableTreeNode OldNode = null;
               TreePath OldPath = e.getOldLeadSelectionPath();
               if(OldPath != null){
                   OldNode = (DefaultMutableTreeNode)OldPath.getLastPathComponent();
               }
               if(node != null){
                   selectItem(node, OldNode);
               }else{
                   Main.debug_out("NULL Selection");
               }
           } 
        });
        
        
        
    }
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////    
    public boolean closeMe(){
        // Need to check modified and save statuses
        //initTree();
        
        DefaultMutableTreeNode Root = (DefaultMutableTreeNode)((DefaultTreeModel)treeModel).getRoot();
        if(Root.getChildCount() > 0){
            DefaultMutableTreeNode Child = (DefaultMutableTreeNode)Root.getFirstChild();
            while(Child != null){
                PTDDeclInfo aDecl = (PTDDeclInfo) Child.getUserObject();
                if(aDecl != null){
                    if(aDecl.myData.myType == DeclBase.TYPE_FILE){
                        if(aDecl.myData.bModifiedFlag){
                            String sMess = "The Declarations file '" + aDecl.myData.myName + "' has been modified.  Do you want to save it?";
                            int iSel = PTDMain.saveConfirm(sMess, "Declarations Modified");
                            if(iSel == JOptionPane.CANCEL_OPTION){
                                return false;
                            }else if(iSel == JOptionPane.YES_OPTION){
                                saveFile(aDecl.myData.myName, Child);
                            }
                        }
                    }
                }
                Child = Child.getNextSibling();
            }
        }
        
        
        return true;
    }
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////    
    public void ShowDeclsPopup(int X, int Y){
        DeclsPopup.show(this, X, Y);
    }
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    public void GenerateMenus(){
        DeclsPopup = new JPopupMenu();

        InsertChild = new JMenuItem("Insert Child");
        InsertChild.setMnemonic('C');
        InsertChild.setToolTipText("Inserts a new child window");
        DeclsPopup.add(InsertChild);

        InsertBefore = new JMenuItem("Insert Before");
        InsertBefore.setMnemonic('B');
        InsertBefore.setToolTipText("Inserts a new sibling window before the selected item");
        DeclsPopup.add(InsertBefore);
        
        InsertAfter = new JMenuItem("Insert After");
        InsertAfter.setMnemonic('A');
        InsertAfter.setToolTipText("Inserts a new sibling window after the selected item");
        DeclsPopup.add(InsertAfter);

        EditDeleteMenu = new JMenuItem("Delete");
        EditDeleteMenu.setToolTipText("Deletes the selected item");
        EditDeleteMenu.setMnemonic('D');

        EditMenu = new JMenu("Edit");
        EditMenu.setMnemonic('E');
        
        EditCopyMenu = new JMenuItem("Copy");
        EditCopyMenu.setToolTipText("Copies the selected item to a buffer");
        EditCopyMenu.setMnemonic('C');
        EditPasteInMenu = new JMenuItem("Paste In");
        EditPasteInMenu.setToolTipText("Pastes a window as a child to the selected item");
        EditPasteInMenu.setMnemonic('I');
        
        EditPasteAfterMenu = new JMenuItem("Paste After");
        EditPasteAfterMenu.setToolTipText("Pastes a window as a sibling after the selected item");
        EditPasteAfterMenu.setMnemonic('A');
        
        EditPasteBeforeMenu = new JMenuItem("Paste Before");
        EditPasteBeforeMenu.setToolTipText("Pastes a window as a sibling before the selected item");
        EditPasteBeforeMenu.setMnemonic('B');

        
        EditMenu.add(EditCopyMenu);
        EditMenu.add(EditPasteInMenu);
        EditMenu.add(EditPasteBeforeMenu);
        EditMenu.add(EditPasteAfterMenu);
        EditMenu.add(EditDeleteMenu);

        EditPasteInMenu.setEnabled(false);
        EditPasteBeforeMenu.setEnabled(false);
        EditPasteAfterMenu.setEnabled(false);

        DeclsPopup.add(EditMenu);
        
        
        EditMenu.setFont(new java.awt.Font("Arial", 0, 12));
        EditCopyMenu.setFont(new java.awt.Font("Arial", 0, 12));
        EditPasteInMenu.setFont(new java.awt.Font("Arial", 0, 12));
        EditPasteBeforeMenu.setFont(new java.awt.Font("Arial", 0, 12));
        EditPasteAfterMenu.setFont(new java.awt.Font("Arial", 0, 12));
        EditDeleteMenu.setFont(new java.awt.Font("Arial", 0, 12));
        InsertChild.setFont(new java.awt.Font("Arial", 0, 12));
        InsertAfter.setFont(new java.awt.Font("Arial", 0, 12));
        InsertBefore.setFont(new java.awt.Font("Arial", 0, 12));
        
        InsertChild.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                InsertChildMenuActionPerformed(evt);
            }
        });

        InsertAfter.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                InsertAfterMenuActionPerformed(evt);
            }
        });
        
        InsertBefore.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                InsertBeforeMenuActionPerformed(evt);
            }
        });

        EditDeleteMenu.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                DeleteMenuActionPerformed(evt);
            }
        });

        EditCopyMenu.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                EditCopyMenuActionPerformed(evt);
            }
        });

        EditPasteInMenu.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                EditPasteInMenuActionPerformed(evt);
            }
        });

        EditPasteBeforeMenu.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                EditPasteBeforeMenuActionPerformed(evt);
            }
        });
        
        EditPasteAfterMenu.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                EditPasteAfterMenuActionPerformed(evt);
            }
        });
        
        
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    private void InsertChildMenuActionPerformed(java.awt.event.ActionEvent evt) {                                             
        DeclBase NewItem = new DeclBase();
        NewItem.myType = NewItem.TYPE_WIN;
        NewItem.isUseable = true;
        NewItem.myName = "New Window";
        InsertNewItem(NewItem, 0);
    }
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    private void InsertBeforeMenuActionPerformed(java.awt.event.ActionEvent evt) {                                             
        DeclBase NewItem = new DeclBase();
        NewItem.myType = NewItem.TYPE_WIN;
        NewItem.isUseable = true;
        NewItem.myName = "New Window";
        InsertNewItem(NewItem, 1);
    }
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    private void InsertAfterMenuActionPerformed(java.awt.event.ActionEvent evt) {                                             
        DeclBase NewItem = new DeclBase();
        NewItem.myType = NewItem.TYPE_WIN;
        NewItem.isUseable = true;
        NewItem.myName = "New Window";
        InsertNewItem(NewItem, 2);
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    private void DeleteMenuActionPerformed(java.awt.event.ActionEvent evt) {                                             
        DefaultMutableTreeNode aNode = getSelectedTreeNode();
        setModified(aNode);
        DeleteNode(aNode);
    }
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    private void EditCopyMenuActionPerformed(java.awt.event.ActionEvent evt){
        DefaultMutableTreeNode aNode = getSelectedTreeNode();
        CopyNode(aNode, null);
    }
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    private void EditPasteInMenuActionPerformed(java.awt.event.ActionEvent evt) {                                             
        DefaultMutableTreeNode aNode = getSelectedTreeNode();
        DefaultMutableTreeNode tempNode = m_CopyNodes;
        CopyNode(tempNode, null); // This in effect copies m_CopyNodes into a new copy
        PasteNode(tempNode, aNode, 0);
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    private void EditPasteBeforeMenuActionPerformed(java.awt.event.ActionEvent evt) {                                             
        DefaultMutableTreeNode aNode = getSelectedTreeNode();
        DefaultMutableTreeNode tempNode = m_CopyNodes;
        CopyNode(tempNode, null); // This in effect copies m_CopyNodes into a new copy
        PasteNode(tempNode, aNode, 2);
    }
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    private void EditPasteAfterMenuActionPerformed(java.awt.event.ActionEvent evt) {                                             
        DefaultMutableTreeNode aNode = getSelectedTreeNode();
        DefaultMutableTreeNode tempNode = m_CopyNodes;
        CopyNode(tempNode, null); // This in effect copies m_CopyNodes into a new copy
        PasteNode(tempNode, aNode, 1);
    }
    
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    public void InsertNewItem(DeclBase NewItem, int Location){

        PTDDeclInfo NewInfo = new PTDDeclInfo();        
        NewInfo.init(NewItem);
        DefaultMutableTreeNode Node = new DefaultMutableTreeNode(NewInfo, true);
        
        DefaultMutableTreeNode selItem = getSelectedTreeNode();
        if((selItem != null)){
            DefaultMutableTreeNode parItem = (DefaultMutableTreeNode)selItem.getParent();
            if(parItem == null){
                return;
            }
            int index = parItem.getIndex(selItem);
            if(Location == 0){
                //int cnt = selItem.getChildCount();
                ((DefaultTreeModel)treeModel).insertNodeInto(Node, selItem, 0);
            }else if(Location == 1){
                ((DefaultTreeModel)treeModel).insertNodeInto(Node, parItem, index);
            }else{
                ((DefaultTreeModel)treeModel).insertNodeInto(Node, parItem, index+1);
            }
            scrollPathToVisible(new TreePath(Node.getPath()));
            setModified(Node);
        }
        this.selectItem(Node, selItem);
        setSelectionPath(new TreePath(Node.getPath()));
    }
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    private void DeleteNode(DefaultMutableTreeNode aNode){
        try{
            // Remove the selection
            setSelectionRow(0);
            ((DefaultTreeModel)treeModel).removeNodeFromParent(aNode);
        }catch(Exception e){
        }
    }
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    private void CopyNode(DefaultMutableTreeNode aNode, DefaultMutableTreeNode aParent){
        if(aNode == null){
            return;
        }
        if(aParent == null){
            
            PTDDeclInfo anInfo = (PTDDeclInfo)aNode.getUserObject();
            PTDDeclInfo newInfo = new PTDDeclInfo();
            
            DeclBase aBase = new DeclBase();
            newInfo.init(anInfo.myData);        
            boolean AllowChildren = false;

            m_CopyNodes = new DefaultMutableTreeNode(newInfo, true); //(DefaultMutableTreeNode)aNode.clone();
            aParent = m_CopyNodes;
        }
        
        EditPasteInMenu.setEnabled(true);
        EditPasteBeforeMenu.setEnabled(true);
        EditPasteAfterMenu.setEnabled(true);                    

        EditPasteInMenuParent.setEnabled(true);
        EditPasteBeforeMenuParent.setEnabled(true);
        EditPasteAfterMenuParent.setEnabled(true);                    
        
        int i = 0;
        DefaultMutableTreeNode aChild; //= (DefaultMutableTreeNode)aNode.clone();
        for(i = 0; i < aNode.getChildCount(); i++){
            aChild = (DefaultMutableTreeNode)aNode.getChildAt(i);
            PTDDeclInfo anInfo = (PTDDeclInfo)aChild.getUserObject();
            PTDDeclInfo newInfo = new PTDDeclInfo();
            
            DeclBase aBase = new DeclBase();
            newInfo.init(anInfo.myData);        
            aChild = new DefaultMutableTreeNode(newInfo, true);

            CopyNode((DefaultMutableTreeNode)aNode.getChildAt(i), aChild);
            aParent.add(aChild);
        }   
        return;
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    private void PasteNode(DefaultMutableTreeNode aNode, DefaultMutableTreeNode aParent, int iPosition){
        if(aParent == null){
            return;
        }
        if(aNode == null){
            return;
        }   
        DefaultMutableTreeNode pParent = (DefaultMutableTreeNode)aParent.getParent();
        int index = 0;
        if(pParent != null){
            index = pParent.getIndex(aParent);
        }
        
        if(iPosition == 0){
            // Paste Into
            ((DefaultTreeModel)treeModel).insertNodeInto(aNode, aParent, 0);
        }else if(iPosition == 1){
            // Paste After
            if(pParent != null){
                index = index + 1;
                ((DefaultTreeModel)treeModel).insertNodeInto(aNode, pParent, index);
                
            }
        }else{
            // Paste Before
            if(pParent != null){
                ((DefaultTreeModel)treeModel).insertNodeInto(aNode, pParent, index);
            }
        }
        if(pParent != null){
            ((DefaultTreeModel)treeModel).nodeStructureChanged(pParent);
        }
        
        setModified(aNode);        
        DefaultTreeModel model = (DefaultTreeModel)getModel();
        model.nodeChanged(aNode);  
        return;
    }
    
    
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////    
    public void initTree(){
        DeclBase aBase = new DeclBase();
        PTDDeclInfo anInfo = new PTDDeclInfo();
        aBase.myName = "Declarations";
        aBase.myType = DeclBase.TYPE_TOP;
        anInfo.init(aBase);
        DefaultMutableTreeNode Root = new DefaultMutableTreeNode(anInfo, true);
        if(Root != null){
            setSelectionPath(null);
            ((DefaultTreeModel)treeModel).setRoot(Root);
        }        
    }
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    public void PopulateMenu(JMenuItem InMenu, JPopupMenu Source){
        int cnt = Source.getComponentCount();
        int i;
        for(i = 0; i < cnt; i++){
            
            // This should work for both JMenu and JMenuItem
            JMenuItem a = (JMenuItem)Source.getComponent(i);
            Source.insert(a, i);
            
            MenuElement[] elems = a.getSubElements();
            int len = elems.length;
            
            if(len > 0){
                JMenu b;
                if(a == EditMenu){
                    EditMenuParent = new JMenu(a.getText());
                    EditMenuParent.setEnabled(false);
                    b = EditMenuParent;
                }else{
                    b = new JMenu(a.getText());
                }
                
                b.setMnemonic(a.getMnemonic());
                b.setToolTipText(a.getToolTipText());
                PopulateMenu(b, (JPopupMenu)elems[0]);

                b.setFont(new java.awt.Font("Arial", 0, 12));
                InMenu.add(b);
            }else{

                JMenuItem b;                
                if(a == EditDeleteMenu){
                    EditDeleteMenuParent = new JMenuItem(a.getText());
                    b = EditDeleteMenuParent;
                }else if(a == EditCopyMenu){
                    EditCopyMenuParent = new JMenuItem(a.getText());
                    b = EditCopyMenuParent;                                                            
                }else if(a == EditPasteInMenu){
                    EditPasteInMenuParent = new JMenuItem(a.getText());
                    b = EditPasteInMenuParent;                                       
                    EditPasteInMenuParent.setEnabled(false);
                }else if(a == EditPasteAfterMenu){
                    EditPasteAfterMenuParent = new JMenuItem(a.getText());
                    b = EditPasteAfterMenuParent;
                    EditPasteAfterMenuParent.setEnabled(false);
                }else if(a == EditPasteBeforeMenu){
                    EditPasteBeforeMenuParent = new JMenuItem(a.getText());
                    b = EditPasteBeforeMenuParent;
                    EditPasteBeforeMenuParent.setEnabled(false);
                }else if(a == InsertChild){
                    InsertChildParent = new JMenuItem(a.getText());
                    b = InsertChildParent;                                                            
                    InsertChildParent.setEnabled(false);
                }else if(a == InsertBefore){
                    InsertBeforeParent = new JMenuItem(a.getText());
                    b = InsertBeforeParent;             
                    InsertBeforeParent.setEnabled(false);
                }else if(a == InsertAfter){
                    InsertAfterParent = new JMenuItem(a.getText());
                    b = InsertAfterParent;                                                                                
                    InsertAfterParent.setEnabled(false);
                }else{
                    b = new JMenuItem(a.getText());
                }
                
                b.setToolTipText(a.getToolTipText());
                b.setMnemonic(a.getMnemonic());
                java.awt.event.ActionListener[] l = a.getActionListeners();
                len = l.length;
                while(len > 0){
                    b.addActionListener(l[len-1]);
                    len = len - 1;
                }
                b.setFont(new java.awt.Font("Arial", 0, 12));
                InMenu.add(b);
            }
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    public void EnableParentMenus(boolean bEnable){
        InsertChildParent.setEnabled(bEnable);
        InsertBeforeParent.setEnabled(bEnable);
        InsertAfterParent.setEnabled(bEnable);
        
        EditMenuParent.setEnabled(bEnable);
        EditCopyMenuParent.setEnabled(bEnable);
        // These depend on copy node state, leave as is (Edit Menu will remain)
        //EditPasteInMenuParent.setEnabled(bEnable);
        //EditPasteBeforeMenuParent.setEnabled(bEnable);
        //EditPasteAfterMenuParent.setEnabled(bEnable);
        EditDeleteMenuParent.setEnabled(bEnable);
        
    }
    
    
   public void updateUI() {
       if(bStaticUI == false){
           setUI(UIManager.getUI(this));
       }
       // Dont want this UI to change
   }
   
   public void updateSelectedItem(){
        DefaultMutableTreeNode SelNode = getSelectedTreeNode();
        if(SelNode == null){
            return;
        }
        
        TreePath selPath = new TreePath(SelNode.getPath());
        clearSelection();
        setSelectionPath(selPath);
        DefaultTreeModel model = (DefaultTreeModel)getModel();
        setModified(SelNode);
        model.nodeChanged(SelNode);  
    }

    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    // PTDDeclInfo ///////////////////////////////////////
    public class PTDDeclInfo extends Object{
        public DeclBase myData;
        public PTDDeclsFrame myFrame;
        
        // -----------------------------------------------------
        public PTDDeclInfo(){
            myData = null;
            myFrame = null;
        }
        
        // -----------------------------------------------------
        public void init(DeclBase newData){
            myData = newData.duplicate();
            myFrame = new PTDDeclsFrame(myData);
        }
        
    }
    // END PTDNodeInfo ///////////////////////////////////////
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    // PTDDECLSCELL ///////////////////////////////////////
    // Used for when the cell is editable
    public class PTDDeclsCell implements TreeCellEditor{
        
        // -----------------------------------------------------
        public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row){
            DefaultMutableTreeNode node =  (DefaultMutableTreeNode)value;

            if(node.isLeaf() || node.getAllowsChildren())
            {
                PTDDeclInfo anInfo = (PTDDeclInfo)node.getUserObject();                
                anInfo.myFrame.setSelectState(true);
                anInfo.myFrame.update(anInfo.myData);
                return anInfo.myFrame;
            }
            else
            {
                return new JLabel("Error");
            }
        }
        
        // -----------------------------------------------------
        public void addCellEditorListener(CellEditorListener l){
            
        }

        // -----------------------------------------------------
        public void removeCellEditorListener(CellEditorListener l){
            
        }
        
        // -----------------------------------------------------
        public Object getCellEditorValue(){
            return this;
        }
        
        // -----------------------------------------------------
        public void cancelCellEditing(){
        }
 
        // -----------------------------------------------------
        public boolean stopCellEditing(){
            return true;
        }
 
        // -----------------------------------------------------
        public boolean isCellEditable(EventObject isEditableEvt){
            if (isEditableEvt instanceof MouseEvent){
                MouseEvent me = (MouseEvent) isEditableEvt;
                if (me.getClickCount() == 1){
                    return true;
                }
            }
            return false;
        }
        
        // -----------------------------------------------------
        public boolean shouldSelectCell(EventObject selectCell){
            return true;
        }
    }
    // END PTDTreeCell ///////////////////////////////////////

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    // PTDDeclsRender ///////////////////////////////////////
    // Used to render the tree item under non-edit circumstances
    public class PTDDeclsRender extends DefaultTreeCellRenderer{
        
        //public boolean isInitialized;
        
        // -----------------------------------------------------
        public PTDDeclsRender(){
            //isInitialized = false;
        }
 
        // -----------------------------------------------------
        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus){
            DefaultMutableTreeNode node =  (DefaultMutableTreeNode)value;
            //if(isInitialized == false){
            //    return new JLabel("Ugh");
            //}
            
            PTDDeclInfo anInfo = (PTDDeclInfo)node.getUserObject();
            if(anInfo == null){
              return new JLabel("Error");  
            }
            //Main.debug_out(anInfo.myName);
            if(selected){
                anInfo.myFrame.setSelectState(true);
            }else{
                anInfo.myFrame.setSelectState(false);
            }
            anInfo.myFrame.update(anInfo.myData);
            return anInfo.myFrame;

        }
        
    }
    // END PTDTreeRender ///////////////////////////////////////

        ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    // PTDTreeFrame ///////////////////////////////////////
    public class PTDDeclsFrame extends JPanel{
        public JLabel myLabel;
        public Icon myIcon;
        
        // -----------------------------------------------------
        public PTDDeclsFrame(DeclBase InData){
            
            myLabel = new JLabel(InData.myName);
            //if(inParent.myType == inParent.SUITE_TYPE){
            if(InData.myType == DeclBase.TYPE_TOP){
                //myIcon = PTDImageLoader.getImageIcon(PTDImageLoader.IMG_SUITE_ICON);
                myIcon = null;
            }else if(InData.myType == DeclBase.TYPE_FILE){
                myIcon = PTDImageLoader.getImageIcon(PTDImageLoader.IMG_DECL_FILE);
            }else if(InData.myType == DeclBase.TYPE_WIN){
                myIcon = PTDImageLoader.getImageIcon(PTDImageLoader.IMG_DECL_ICON);
            }
            myLabel.setIcon(myIcon);
            
            setLayout(new java.awt.GridBagLayout());

            myLabel.setFont(new java.awt.Font("Arial", 0, 12));
            myLabel.setBackground(Color.WHITE);
            this.setBackground(Color.WHITE);
            add(myLabel);
            
        }

        
        // -----------------------------------------------------
        public void setSelectState(boolean selState){
            if(selState){
                Color LtBlue = new Color(200, 220, 255);
                myLabel.setBackground(LtBlue);
                this.setBackground(LtBlue);
            }else{
                myLabel.setBackground(Color.WHITE);
                this.setBackground(Color.WHITE);
            }
        }
        
        public void update(DeclBase Info){
            if(Info.bModifiedFlag){
                myLabel.setText(Info.myName + " *");
            }else{
                myLabel.setText(Info.myName);
            }
        }
        
        
    }
    // END PTDTreeFrame ///////////////////////////////////////

    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    public class PTDDeclsMouseListener extends MouseAdapter{
    /*            
    Use the getPathForLocation method first on the JTree object to get the TreePath 
    TreePath selPath = jtree.getPathForLocation(e.getX(), e.getY()); 
    (Here, e is the MouseEvent object) 

    Next use the getLastPathComponent method to get the DefaultMutableTreeNode 
    DefaultMutableTreeNode selectedNode = null;
    try { selectedNode = (DefaultMutableTreeNode)selPath.getLastPathComponent(); }
    catch (Exception E){} 
    selectedNode returns null if the event did not occur on an object of type DefaultMutableTreeNode
    */            
        // -----------------------------------------------------
        public void mousePressed(MouseEvent e) {
            // Required to allow keyboard navigation when a tree item is selected.
            requestFocus();
            EnableParentMenus(false);
            
            if(pW == null){
                return;
            }

            TreePath selPath = getPathForLocation(e.getX(), e.getY());
            if(selPath == null){
                return;
            }
            DefaultMutableTreeNode selNode = (DefaultMutableTreeNode)selPath.getLastPathComponent();
            if(selNode == null){
                return;
            }

            if(selNode != null){
                PTDDeclInfo Info = (PTDDeclInfo)selNode.getUserObject();
                if(Info != null){
                    if(Info.myData.myType == Info.myData.TYPE_WIN){
                        EnableParentMenus(true);
                        if(e.getButton() == e.BUTTON3){                            
                            ShowDeclsPopup(e.getX(), e.getY());
                        }
                    }
                }
            }
        }
    }
    
    
    
}
